#include "StatePattern.hpp"

// bool isOperators(char c)
// {
//     if (punctuation.find(c) != punctuation.end())
//         return true;
//     return false;
// }

void Token::resetToken()
{
    this->value.clear();
    this->info.clear();
    this->type = 0;
    this->state = OTHER;
}

Token KeywordState::getToken(std::string::const_iterator char_ptr)
{
    token.resetToken();

#ifdef LEX_KEYWORD_UPPERCASE
    /* 字母包含大写字母 */
    do
    {
        token.value.push_back(*char_ptr);
        char_ptr++;
    } while (std::isalpha(*char_ptr));

    /* keyword */
    if (!std::isalnum(*char_ptr))
    {
        std::map<std::string, int>::const_iterator it = TokenTable.find(token.value);
        if (it != TokenTable.end())
        {
            token.type = it->second;
            token.state = ACCEPT;
            return token;
        }
    }

    /* identifier */
    while (std::isalnum(*char_ptr))
    {
        token.value.push_back(*char_ptr);
        char_ptr++;
    }

#else
    /* 字母仅为小写字母 a-z */
    while (std::islower(*char_ptr))
    {
        token.value.push_back(*char_ptr);
        char_ptr++;
    }

    /* keyword */
    if (!std::isalnum(*char_ptr))
    {
        std::map<std::string, int>::const_iterator it = TokenTable.find(token.value);
        if (it != TokenTable.end())
        {
            token.type = it->second;
            token.state = ACCEPT;
            return token;
        }
    }

    /* identifier */
    while (std::isdigit(*char_ptr) || std::islower(*char_ptr))
    {
        token.value.push_back(*char_ptr);
        char_ptr++;
    }

    /* 包含大写字母非法 */
    if (std::isupper(*char_ptr))
    {
        do
        {
            token.value.push_back(*char_ptr);
            char_ptr++;
        } while (std::isalnum(*char_ptr));

        token.type = -1;
        token.state = ERROR_ILLEGALCHAR;
        token.info = "包含大写字母";
        return token;
    }

#endif

    if (token.value.length() <= IDENTIFIER_LEN)
    {
        token.type = IDENTIFIER_TYPE;
        token.state = ACCEPT;
    }
    else
    {
        token.type = -1;
        token.state = ERROR_IDENTIFIER_OVERFLOW;
    }

    return token;
}

Token OperatorState::getToken(std::string::const_iterator char_ptr)
{
    token.resetToken();

    char first_char = *char_ptr;
    token.value.push_back(*char_ptr);
    char_ptr++;

    /* BinaryOperator ':=', '>', '>=', '<', '<=', '<>' */
    if (first_char == ':' || first_char == '>' || first_char == '<')
    {
        if(std::ispunct(*char_ptr))
            token.value.push_back(*char_ptr);
#ifdef RELATIONAL_OPERATOR_ONLY_BINARY
        else
        {
            token.type = -1;
            token.state = ERROR_ILLEGALCHAR;
            token.info = "<关系运算符> 仅为二元运算符";
            return token;
        }
#endif
    }

    std::map<std::string, int>::const_iterator it = TokenTable.find(token.value);
    if (it != TokenTable.end())
    {
        token.type = it->second;
        token.state = ACCEPT;
    }
    else
    {
        token.type = -1;
        if (first_char == ':')
        {
            token.state = ERROR_COLON_MATCH;
            token.info = "唯一用法':='";
        }
        else if (first_char == '>')
        {
            token.state = ERROR_ILLEGALCHAR;
            token.info = "'>'非法组合";
        }
        else if (first_char == '<')
        {
            token.state = ERROR_ILLEGALCHAR;
            token.info = "'<'非法组合";
        }
        else
        {
            token.state = ERROR_ILLEGALCHAR;
            token.info = "此符号不支持";
        }
    }

    return token;
}

Token ConstantState::getToken(std::string::const_iterator char_ptr)
{
    token.resetToken();

    do
    {
        token.value.push_back(*char_ptr);
        char_ptr++;
    } while (std::isdigit(*char_ptr));

    /* end with alpha */
    if (std::isalpha(*char_ptr))
    {
        do
        {
            token.value.push_back(*char_ptr);
            char_ptr++;
        } while (std::isalnum(*char_ptr));

        token.type = -1;
        token.state = ERROR_ILLEGALCHAR;
        token.info = "标识符不能以数字开头";
        return token;
    }

    if (token.value.length() <= CONSTANT_LEN)
    {
        token.type = CONSTANT_TYPE;
        token.state = ACCEPT;
    }
    else
    {
        token.type = -1;
        token.state = ERROR_CONSTANT_OVERFLOW;
    }

    return token;
}

Token OtherPunctuationState::getToken(std::string::const_iterator char_ptr)
{
    token.resetToken();

    do
    {
        token.value.push_back(*char_ptr);
        char_ptr++;
    } while (!(std::isalnum(*char_ptr) || std::isspace(*char_ptr) || std::ispunct(*char_ptr)));

    token.type = -1;
    token.state = ERROR_ILLEGALCHAR;
    token.info = "未知字符错误";

    return token;
}